package coherence;
import java.util.List;
import multiarray.MultiArray;



public class Utilities{
	
	private MultiArray<MultiArray<Float>> altruisms;
	private MultiArray<Float> powerByCrossSection;
	private List<List<int []>> partition;
	private boolean[][] won_i_j;
	private MultiArray<Float> populationByCrossSection;	
	
	private float lambda = 0.5f;
	private float c = 0.5f;
	private float I = 1;
	private float epsilon = 0.1f;
	
	private int numCoalitions;
	private float[] sigma_i;
	private int[] coalitionSizes;
	private float[][] theta_i_j;
	private float[][][] tau_i_j_n;
	private float[][] beta_i_j;
	private float[] pi_i;
	private float[][][] phi_i_j_k;
	float[][] psi_i_j;
	
	private float[][][] computeTaus(){
		float[][][] result = new float[numCoalitions][numCoalitions][];
		for(int i = 0; i < numCoalitions; i++)
			for(int j = 0; j < numCoalitions; j++){
				result[i][j] = new float[coalitionSizes[i]];
				for(int k = 0; k < numCoalitions; k++)
					result[i][j][k] = theta_i_j[i][j]/sigma_i[i];
			}
		return result;
	}
	
	private float[][][] computeRewards(float[] pi_j, boolean[][] i_beat_j){
		float[][][] result = new float[numCoalitions][numCoalitions][];
		for(int i = 0; i < numCoalitions; i++)
			for(int j = 0; j < numCoalitions; j++){
				result[i][j] = new float[coalitionSizes[i]];
				if(i_beat_j[i][j] == false) continue;
				for(int k = 0; k < numCoalitions; k++)
					result[i][j][k] = lambda/(sigma_i[i]*(numCoalitions -1))*pi_i[j];
			}
		return result;
	}	
	
	private float[][][] computeLosses(float[] pi_i, boolean[][] i_beat_j){
		float[][][] result = new float[numCoalitions][numCoalitions][];
		for(int i = 0; i < numCoalitions; i++)
			for(int j = 0; j < numCoalitions; j++){
				result[i][j] = new float[coalitionSizes[i]];
				if(i_beat_j[i][j] == true) continue;
				for(int k = 0; k < numCoalitions; k++)
					result[i][j][k] = lambda/(sigma_i[i]*(numCoalitions -1))*pi_i[i];
			}
		return result;
	}		

	private float[][][] computeExpenditure(){
		float[][][] result = new float[numCoalitions][numCoalitions][];
		for(int i = 0; i < numCoalitions; i++)
			for(int j = 0; j < numCoalitions; j++){
				result[i][j] = new float[coalitionSizes[i]];
				for(int k = 0; k < numCoalitions; k++)
					result[i][j][k] = c*tau_i_j_n[i][j][k];
			}
		return result;
	}
	
	private float getReward(int i , int j){
		return lambda/(sigma_i[i]*(numCoalitions -1))*pi_i[j];
	}
	
	private float getLoss(int i , int j){
		return lambda/(sigma_i[i]*(numCoalitions -1))*pi_i[i];
	}	
	
	private float getWinningRatio(int i , int j){
		return theta_i_j[i][j]/(epsilon + theta_i_j[i][j] + theta_i_j[j][i]);
	}
	
	private float getWinningRatioFreeRide(int i , int j, int k){
		return get_theta_i_j_minus_k(i,j,k)/(epsilon + get_theta_i_j_minus_k(i,j,k) + theta_i_j[j][i]);
	}
	
	private float getLosingRatioFreeRide(int i , int j, int k){
		return theta_i_j[j][i]/(epsilon + get_theta_i_j_minus_k(i,j,k) + theta_i_j[j][i]);
	}	
	
	private float getExpenditure(int i , int j, int k){
		return c*tau_i_j_n[i][j][k];
	}
	
	private float get_theta_i_j_minus_k(int i , int j, int k){
		return theta_i_j[i][j] - tau_i_j_n[i][j][k];
	}
	
	private float get_U_Contribute_Prospective(int i , int j, int k){
		float netGain = getReward(i,j)+getWinningRatio(i,j) + 
		getLoss(i,j)*getWinningRatio(j,i) -
		getExpenditure(i,j,k);
		return phi_i_j_k[i][j][k] + (1 - I)*netGain;
	}
	
	private float get_U_FreeRide_Prospective(int i , int j, int k){
		float netGain = getReward(i,j)+getWinningRatioFreeRide(i,j,k) + 
		getLoss(i,j)*getLosingRatioFreeRide(i,j,k);
		return phi_i_j_k[i][j][k] + (1 - I)*netGain;
	}	
	
	private float get_U_Contribute_Lose_Retrospective(int i , int j, int k){
		float netGain = getLoss(i,j) - getExpenditure(i,j,k);
		return netGain;
	}	
	
	private float get_U_FreeRide_Lose_Retrospective(int i , int j, int k){
		float gain = getLoss(i,j);
		return gain;
	}	
	
	private float getLossRegret(int i , int j, int k){
		return getExpenditure(i,j,k);
	}
	
	private float[][][] computeUtilityContribute(){
		float[][][] result = new float[numCoalitions][numCoalitions][];
		for(int i = 0; i < numCoalitions; i++)
			for(int j = 0; j < numCoalitions; j++){
				result[i][j] = new float[coalitionSizes[i]];
				for(int k = 0; k < numCoalitions; k++)
					result[i][j][k] = phi_i_j_k[i][j][k] + (1 - I)*(theta_i_j[i][j]);
			}
		return result;
	}
	
	private float get_Regret_Contribute_Lose(int i , int j, int k){
		
		float beta_sum = 0;
		for(int m = 0; m < coalitionSizes[j]; m++){
			beta_sum += beta_i_j[i][j];
		}
		
		float regret = c*tau_i_j_n[i][j][k] + lambda * tau_i_j_n[i][j][k]/sigma_i[j]*beta_sum;
		
		if(regret >= 0) return regret;
		else return 0;
	}
	
	private void update_Betas_Contribute_Lose(int i , int j, int k){
		float beta_sum = 0;
		for(int m = 0; m < coalitionSizes[j]; m++){
			beta_sum += beta_i_j[i][m];
		}
		//beta_i_j[i][j] += 
	}
	
}
